home *** CD-ROM | disk | FTP | other *** search
- ╒═══════════════════════════════╕
- │ W E L C O M E │
- │ To the VGA Trainer Program │ │
- │ By │ │
- │ DENTHOR of ASPHYXIA │ │ │
- ╘═══════════════════════════════╛ │ │
- ────────────────────────────────┘ │
- ────────────────────────────────┘
-
- --==[ PART 19 ]==--
-
-
-
- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
- ■ Introduction
-
- Hi there. As promised in Tut 18, this trainer is on assembler. For those
- people who already know assembler quite well, this tut is also on the flame
- effect.
-
- Okay, here is the total list of ways to get my trainers :
-
- http://goth.vironix.co.za/~denthor (WWW)
- ftp.eng.ufl.edu pub/msdos/demos/code/graph/tutor (FTP)
- denthor@beastie.cs.und.ac.za Subject : request-list (EMAIL)
-
- As well as the BBS numbers shown at the end ... I will add a few ftp sits
- to that list (x2ftp.oulu.fi etc.)
-
- Tut 20? How about 3d shading, hidden surface removal etc? Mail me :)
-
-
- If you would like to contact me, or the team, there are many ways you
- can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
- on the ASPHYXIA BBS.
- 2) Write to : Grant Smith
- P.O.Box 270 Kloof
- 3640
- Natal
- South Africa
- 3) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
- call during varsity). Call +27-31-73-2129 if you call
- from outside South Africa. (It's YOUR phone bill ;-))
- 4) Write to denthor@beastie.cs.und.ac.za in E-Mail.
- 5) Write to asphyxia@beastie.cs.und.ac.za to get to all of
- us at once.
-
- NB : If you are a representative of a company or BBS, and want ASPHYXIA
- to do you a demo, leave mail to me; we can discuss it.
- NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
- quite lonely and want to meet/help out/exchange code with other demo
- groups. What do you have to lose? Leave a message here and we can work
- out how to transfer it. We really want to hear from you!
-
- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
- ■ Assembler - the short version
-
- Okay, there are many assembler trainers out there, many of which are
- probably better then this one. I will focus on the areas of assembler that
- I find important ... if you want more, go buy a book (go for the Michael
- Abrash ones), or scour the 'net for others.
-
- First, let us start off with the basic set up of an assembler program.
-
- DOSSEG
-
- This tells your assembler program to order your segments in the same manner
- that high level languages do.
-
- .MODEL <MODEL>
-
- <MODEL> can be : Tiny Code + Data < 64k (Can be made a COM file)
- Small Code < 64k Data < 64k
- Medium Code > 64k Data < 64k
- Compact Code < 64k Data > 64k
- Large Code > 64k Data > 64k
- Huge Arrays > 64k
-
- .286
-
- Enable 286 instructions ... can be .386 ; .386P etc.
-
- .STACK <size>
-
- <size> will be the size of your stack. I usually use 200h
-
- .DATA
-
- Tells the program that the data is about to follow. (Everything after this
- will be placed in the data segment)
-
- .CODE
-
- Tells the program that the code is about to follow. (Everything after this
- will be placed in the code segment)
-
- START :
-
- Tells the program that this is where the code begins.
-
- END START
-
- Tells the program that this is where the code ends.
-
- To compile and run an assembler file, we run
- tasm bob
- tlink bob
-
- I personally use tasm, you will have to find out how your assembler works.
-
- Now, if we ran the above file as follows :
-
- DOSSEG
- .MODEL SMALL
- .286
- .STACK 200h
- .DATA
- .CODE
-
- START
- END START
-
- You would think that is would just exit to dos immediately, right? Wrong.
- You have to specifically give dos back control, by doing the following :
-
- START
- mov ax,4c00h
- int 21h
- END START
-
- Now if you compiled it, it would run and do nothing.
-
- Okay, let us kick off with registers.
-
- Firstly : A bit is a value that is either 1 or 0
-
- This is obviously quite limited, but if we start counting in them, we can
- get larger numbers. Counting with ones and zeros is known as binary, and we
- call it base 2. Counting in normal decimal is known as base 10, and
- counting in hexidecimal is known as base 16.
-
- Base 2 (Binary) Base 10 (Decimal) Base 16 (Hexidecimal)
- 0 0 0
- 1 1 1
- 10 2 2
- 11 3 3
- 100 4 4
- 101 5 5
- 110 6 6
- 111 7 7
- 1000 8 8
- 1001 9 9
- 1010 10 A
- 1011 11 B
- 1100 12 C
- 1101 13 D
- 1110 14 E
- 1111 15 F
-
- As you can see, you need four bits to count up to 15, and we call this a
- nibble. With eight bits, we can count up to 255, and we call this a byte.
- With sixteen bits, we can count up to 65535, and we call this a word. With
- thirty two bits, we can count up to lots, and we call this a double word. :)
-
- A quick note : Converting from binary to hex is actually quite easy. You
- break up the binary into groups of four bits, starting on the right, and
- convers these groups of four to hex.
-
- 1010 0010 1111 0001
- = A 2 F 1
-
- Converting to decimal is a bit more difficult. What you do, is you multiply
- each number by it's base to the power of it's index ...
-
- A2F1 hex
- = (A*16^3) + (2*16^2) + (F*16^1) + (1*16^0)
- = (10*4096) + (2*256) + (15*16) + (1)
- = 40960 + 512 + 240 + 1
- = 41713 decimal
-
- The same system can be used for binary.
-
- To convert from decimal to another base, you divide the decimal value by the
- desired base, keeping a note of the remainders, and then reading the results
- backwards.
-
- 16 | 41713
- 16 | 2607 r 1 (41713 / 16 = 2607 r 1)
- 16 | 162 r F (2607 / 16 = 162 r 15)
- 16 | 10 r 2 (162 / 16 = 10 r 2)
- | 0 r A (10 / 16 = 0 r 10)
-
- Read the remainders bacckwards, our number is : A2F1 hex. Again, the same
- method can be used for binary.
-
- The reason why hex is popular is obvious ... using bits, it is impossible
- to get a reasonable base 10 (decimal) system going, and binary get's unwieldly
- at high values. Don't worry too much though : most assemblers (like Tasm)
- will convert all your decimal values to hex for you.
-
- You have four general purpose registers : AX, BX, CX and DX
- Think of them as variables that you will always have. On a 286, these
- registers are 16 bytes long, or one word.
-
- As you know, a word consists of two bytes, and in assembler you can access
- these bytes individualy. They are separated into high bytes and low bytes per
- word.
-
- High Byte | Low Byte
- 0000 0000 | 0000 0000 bits
- [--------Word-------]
-
- The method of access is easy. The high byte of AX is AH, and the low byte is
- AL ... you can also access BH, BL, CH, CL, DH and DL.
-
- A 386 has extended registers : EAX, EBX, ECX, EDX ... you can access the
- lower word normally (as AX, with bytes AH and AL), but you cannot access the
- high word directly ... you must ror EAX,16 (rotate the binary value through
- 16 bits), after which the high word and low word swap ... do it again to
- return them. Acessing EAX as a whole is no problem ... mov eax,10 ;
- add eax,ebx ... these are all vaild.
-
- Next come segments. As you have probably heard, computer memory is divided
- into various 64k segments (note : 64k = 65536 bytes, sound familiar?) A
- segment register points to which segment you are looking at. An offset
- register points to how far into that segment you are looking. One way
- of looking at it is like looking at a 2d array ... the segments are your
- columns and your offsets are your rows. Segments and offsets are displayed
- as Segment:Offset ... so $a000:50 would mean the fiftieth byte in segment
- $a000.
-
- The segment registers are ES, DS, SS and CS. A 386 also has FS an GS.
- These values are words (0-65535), and you cannot access the high or low bytes
- separately. CS points to you your code segment, and usually if you touch this
- your program will explode. SS points to your stack segment, again, this
- baby is dangerous. DS points to your data segment, and can be altered, if
- you put it back after you use it, and don't use any global variables while
- it is altered. ES is your extra segment, and you can do what you want with
- it.
-
- The offset registers are DI, SI, IP, SP, BP. Offset registers are generally
- asscociated with specific segment registers, as follows :
- ES:DI DS:SI CS:IP SS:SP ... On a 286, BX can be used instead of the above
- offset registers, and on a 386, any register may be used. DS:BX is therefore
- valid.
-
- If you create a global variable (let's say bob), when you access that
- variable, the compiler will actually look for it in the data segment.
- This means that the statement :
-
- ax = bob
- could be
- ax = ds:[15]
-
- A quick note : A value may be signed or unsigned. An unsigned word has a
- range from 0 to 65535. A signed word is called an integer and has a range
- -32768 to 32767. With a signed value, if the leftmost bit is equal to 1,
- the value is in the negative.
-
- Next, let us have a look at the stack. Let us say that you want to save the
- value in ax, use ax to do other things, then restore it to it's origional
- value afterwards. This is done by utilising the stack. Have a look at the
- following code :
-
- mov ax, 50 ; ax is equal to 50
- push ax ; push ax onto the stack
- mov ax, 27 ; ax is equal to 27
- pop ax ; pop ax off the stack
- At this point, ax is equal to 50.
-
- Remember we defined the stack to be 200h further up? This is part of the
- reason we have it. When you push a value onto the stack, that value is
- recorded on the stack heap (referenced by SS:SP, SP is incremented) When you
- pop a value off the stack, the value is placed into the variable you are
- poping it back in to, SP is decremented and so forth. Note that the computer
- does not care what you pop the value back in to ...
-
- mov ax, 50
- push ax
- pop bx
-
- Would set the values of both ax and bx to 50. (there are faster ways of doing
- this, pushing and poping are fairly fast though)
-
- push ax
- push bx
- pop ax
- pop bx
-
- would swap the values of ax and bx. As you can see, to pop the values back
- in to the origional variables, you must pop them back in the opposite
- direction to which you pushed them.
-
- push ax
- push bx
- push cx
-
- pop cx
- pop bx
- pop ax
-
- would result in no change for any of the registers.
-
- When a procedure is called, all the parameters for that procedure are pushed
- onto the stack. These can actually be read right off the stack, if you want
- to.
-
- As you have already seen, the mov command moves a value...
-
- mov <dest>, <source>
-
- Note that dest and source must be the same number of bits long...
-
- mov ax, dl
-
- would not work, and neither would
-
- mov cl,bx
-
- However, mov cx,dx
- mov ax,50
- mov es,ax
- are all valid.
-
- Shl I have explained before, it is where all the bits in a register are
- shifted one to the left and a zero added on to the right. This is the
- eqivalent of multiplying the value by two. Shr works in the opposite
- direction.
-
- Rol does the same, except that the bit that is removed from the left is
- replaced on the right hand side. Ror works in the opposite direction.
-
- div <value> divides the value in ax by value and returns the result in
- al if value is a byte, placing the remainder in ah. If value is a word,
- the double word DX:AX is divided by value, the result being placed in ax
- and the remainder in dx. Note that this only works for unsigned values.
-
- idiv <value> does the same as above, but for signed variables.
-
- mul <value> If value is a byte, al is multiplied by value and the result
- is stored in ax. If value is a word, ax is multiplied by value and the
- result is stored in the double word DX:AX
-
- imul <value> does the same as above, but for signed variables.
-
- The j* commands are fairly simple : if a condition is met, jump to a certain
- lable.
-
- jz <label> Jump if zero
- ja <label> Jump above (unsigned)
- jg <label> Jump greater (signed)
-
- and so forth.
-
- An example ...
-
- cmp ax,50 ; Compare ax to 50
- je @Equal ; If they are equal, jump to label @equal
-
- call MyProc Runs procedure MyProc and then returns to the next line of code.
-
- Procedures are declared as follows :
-
- MyProc proc near
- ret ; Must be here to return from where it was called
- MyProc endp
-
- Variables are also easy :
-
- bob db 50
-
- creates a variable bob, a byte, with an initial value of 50.
-
- bob2 dw 50
-
- creates a variable bob2, a word, with an initial value of 50.
-
- bob3 db 1,2,3,4,5,65,23
-
- creates bob3, an array of 7 bytes.
-
- bob4 db 100 dup (?)
-
- creates bob4, an array of 100 bytes, with no starting value.
-
- Go back and look at tut 7 for a whole lot more assembler commands, and get
- some sort of reference guide to help you out with others. I personally use
- the Norton Guides help file to program assembler.
-
-
- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
- ■ Fire Routines
-
- To demonstrate how to write an assembler program, we will write a fire
- routine in 100% assembler. The theory is simple...
-
- Set the pallette to go from white to yellow to red to blue to black.
- Create a 2d array representing the screen on the computer.
- Place high values at the bottom of the array (screen)
- for each element, do the following :
- Take the average of the four elements under it
-
- * Current element
- 123
- 4 Other elements
- Get the average of the four elements, and place the result in the current
- element.
- Repeat
-
- Easy, no? I first saw a fire routine in the Iguana demo, and I just had to
- do one ;) ... it looks very effective.
-
- With the sample file, I have created a batch file, make.bat ... it basically
- says :
- tasm fire
- tlink fire
-
- So to build and run the fire program, type :
- make
- fire
-
- The source file is commented quite well, so there shouldn't be any problems.
-
-
- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
- ■ In closing
-
- As you can see, the sample program is in 100% assembler. For the next tut
- I will return to Pascal, and hopefully your new found assembler skills will
- help you there too.
-
-
-
- Byeeeee....
- - Denthor
-
- The following are official ASPHYXIA distribution sites :
-
- ╔══════════════════════════╦════════════════╦═════╗
- ║BBS Name ║Telephone No. ║Open ║
- ╠══════════════════════════╬════════════════╬═════╣
- ║ASPHYXIA BBS #1 ║+27-31-765-5312 ║ALL ║
- ║ASPHYXIA BBS #2 ║+27-31-765-6293 ║ALL ║
- ║C-Spam BBS ║410-531-5886 ║ALL ║
- ║POP! ║+27-12-661-1257 ║ALL ║
- ║Soul Asylum ║+358-0-5055041 ║ALL ║
- ║Wasted Image ║407-838-4525 ║ALL ║
- ║Reckless Life ║351-01-716 67 58║ALL ║
- ║Mach 5 BBS ║+1 319-355-7336 ║ALL ║
- ║House of Horror ║+1 513-734-6470 ║ALL ║
- ║Zero Level ║+39 6-810-9934 ║ALL ║
- ╚══════════════════════════╩════════════════╩═════╝
-
- Leave me mail if you want to become an official Asphyxia BBS
- distribution site.
- USES crt,dos;
-
- VAR source,dest:string;
-
-
- function Exist(FileName: String): Boolean;
- { Boolean function that returns True if the file exists;otherwise,
- it returns False. Closes the file if it exists. }
- var
- F: file;
- begin
- {$I-}
- Assign(F, FileName);
- FileMode := 0; { Set file access to read only }
- Reset(F);
- Close(F);
- {$I+}
- Exist := (IOResult = 0) and (FileName <> '');
- end;
-
- Procedure GetNames;
- BEGIN
- writeln;
- writeln ('Conversion from binary to db...');
- writeln;
- Write ('Enter name of binary file --> ');
- Readln (source);
- if not exist (source) then BEGIN
- Writeln (source,' not found! Exiting ...');
- writeln;
- halt;
- END;
- Write ('Enter name of desination text file --> ');
- Readln (dest);
- writeln;
- writeln ('Working ...');
- END;
-
- Procedure Convert;
- VAR f:text;
- f2:file;
- loop1,loop2,loop3:integer;
- no:byte;
- msg:string;
- dir:dirstr;
- name:namestr;
- ext:extstr;
- BEGIN
- assign (f2,source);
- reset (f2,1);
- assign (f,dest);
- rewrite (f);
-
- fsplit (dest, dir, name, ext);
- while length (name)<8 do name:=name+' ';
-
- write (f,name,' db ');
- loop1:=0;
- loop3:=filesize (f2);
- loop2:=0;
- While not EOF (f2) do BEGIN
- blockread (f2,no,1);
- str (no:3,msg);
- write (f,msg);
- inc (loop1);
- inc (loop2);
- gotoxy (1,wherey);
- write (loop2,'/',loop3);
- if (loop1=16) and (not (eof(f2))) then BEGIN
- loop1:=0;
- writeln(f);
- write (f,' db ');
- END else
- if not (eof(f2)) then write (f,',');
- END;
-
- close (f);
- close (f2);
- writeln;
-
- writeln ('Done.');
- END;
-
-
- BEGIN
- Getnames;
- Convert;
- END. DOSSEG ; Order the program to order it's segments in the
- ; same way that high level languages do.
-
- .MODEL SMALL ; Different models :
- ; Tiny : Code + Data < 64k (can be made a COM file)
- ; Small : Code < 64k ; Data < 64k
- ; Medium : Code > 64k ; Data < 64k
- ; Compact: Code < 64k ; Data > 64k
- ; Large : Code > 64k ; Data > 64k
- ; Huge : Arrays > 64k
-
- .286 ; Enable 286 instructions
-
- .STACK 200h
-
- .DATA ; Tells compiler that data is to follow.
-
- endmessage db "This was the Fire Effect - denthor@beastie.cs.und.ac.za$"
- ; This is our end message. Must be terminated with a "$"
- xsize = 80 ; The x-width of our screen in pixels
- ysize = 112 ; The y-height of our screen in pixels, plus a few extra
- randseed dw ? ; any number for randomness
-
- pallette db 0, 0, 0, 0, 0, 6, 0, 0, 6, 0, 0, 7, 0, 0, 8, 0, 0, 8, 0, 0, 9, 0, 0,10
- db 2, 0,10, 4, 0, 9, 6, 0, 9, 8, 0, 8,10, 0, 7,12, 0, 7,14, 0, 6,16, 0, 5
- db 18, 0, 5,20, 0, 4,22, 0, 4,24, 0, 3,26, 0, 2,28, 0, 2,30, 0, 1,32, 0, 0
- db 32, 0, 0,33, 0, 0,34, 0, 0,35, 0, 0,36, 0, 0,36, 0, 0,37, 0, 0,38, 0, 0
- db 39, 0, 0,40, 0, 0,40, 0, 0,41, 0, 0,42, 0, 0,43, 0, 0,44, 0, 0,45, 0, 0
- db 46, 1, 0,47, 1, 0,48, 2, 0,49, 2, 0,50, 3, 0,51, 3, 0,52, 4, 0,53, 4, 0
- db 54, 5, 0,55, 5, 0,56, 6, 0,57, 6, 0,58, 7, 0,59, 7, 0,60, 8, 0,61, 8, 0
- db 63, 9, 0,63, 9, 0,63,10, 0,63,10, 0,63,11, 0,63,11, 0,63,12, 0,63,12, 0
- db 63,13, 0,63,13, 0,63,14, 0,63,14, 0,63,15, 0,63,15, 0,63,16, 0,63,16, 0
- db 63,17, 0,63,17, 0,63,18, 0,63,18, 0,63,19, 0,63,19, 0,63,20, 0,63,20, 0
- db 63,21, 0,63,21, 0,63,22, 0,63,22, 0,63,23, 0,63,24, 0,63,24, 0,63,25, 0
- db 63,25, 0,63,26, 0,63,26, 0,63,27, 0,63,27, 0,63,28, 0,63,28, 0,63,29, 0
- db 63,29, 0,63,30, 0,63,30, 0,63,31, 0,63,31, 0,63,32, 0,63,32, 0,63,33, 0
- db 63,33, 0,63,34, 0,63,34, 0,63,35, 0,63,35, 0,63,36, 0,63,36, 0,63,37, 0
- db 63,38, 0,63,38, 0,63,39, 0,63,39, 0,63,40, 0,63,40, 0,63,41, 0,63,41, 0
- db 63,42, 0,63,42, 0,63,43, 0,63,43, 0,63,44, 0,63,44, 0,63,45, 0,63,45, 0
- db 63,46, 0,63,46, 0,63,47, 0,63,47, 0,63,48, 0,63,48, 0,63,49, 0,63,49, 0
- db 63,50, 0,63,50, 0,63,51, 0,63,52, 0,63,52, 0,63,52, 0,63,52, 0,63,52, 0
- db 63,53, 0,63,53, 0,63,53, 0,63,53, 0,63,54, 0,63,54, 0,63,54, 0,63,54, 0
- db 63,54, 0,63,55, 0,63,55, 0,63,55, 0,63,55, 0,63,56, 0,63,56, 0,63,56, 0
- db 63,56, 0,63,57, 0,63,57, 0,63,57, 0,63,57, 0,63,57, 0,63,58, 0,63,58, 0
- db 63,58, 0,63,58, 0,63,59, 0,63,59, 0,63,59, 0,63,59, 0,63,60, 0,63,60, 0
- db 63,60, 0,63,60, 0,63,60, 0,63,61, 0,63,61, 0,63,61, 0,63,61, 0,63,62, 0
- db 63,62, 0,63,62, 0,63,62, 0,63,63, 0,63,63, 1,63,63, 2,63,63, 3,63,63, 4
- db 63,63, 5,63,63, 6,63,63, 7,63,63, 8,63,63, 9,63,63,10,63,63,10,63,63,11
- db 63,63,12,63,63,13,63,63,14,63,63,15,63,63,16,63,63,17,63,63,18,63,63,19
- db 63,63,20,63,63,21,63,63,21,63,63,22,63,63,23,63,63,24,63,63,25,63,63,26
- db 63,63,27,63,63,28,63,63,29,63,63,30,63,63,31,63,63,31,63,63,32,63,63,33
- db 63,63,34,63,63,35,63,63,36,63,63,37,63,63,38,63,63,39,63,63,40,63,63,41
- db 63,63,42,63,63,42,63,63,43,63,63,44,63,63,45,63,63,46,63,63,47,63,63,48
- db 63,63,49,63,63,50,63,63,51,63,63,52,63,63,52,63,63,53,63,63,54,63,63,55
- db 63,63,56,63,63,57,63,63,58,63,63,59,63,63,60,63,63,61,63,63,62,63,63,63
- ; Our pallette ... generated elsewhere and brought in
-
- screen db xsize*ysize dup (?) ; Virtual screen
-
- .CODE ; Tells compiler that code is to follow.
-
-
- Random proc near
-
- mov ax,[RandSeed]
- mov dx,8405h
- mul dx ; ax*dx with result in dx:ax
- inc ax
- mov [RandSeed],ax
- ret ; Return back to main section
-
- Random endp
-
-
-
- SetUpScreen proc near
-
- mov ax,0013h
- int 10h ; Get into 320x200x256 MCGA mode.
-
- mov ax,0a000h
- mov es,ax
- xor di,di ; ES:DI is now pointing to the top left hand of the screen
-
- cli
- cld
- mov dx,3c4h
- mov ax,604h ; Enter unchained mode
- out dx,ax
- mov ax,0F02h ; All planes
- out dx,ax
- xor ax,ax
- mov cx,32767
- rep stosw ; Clear the screen
- mov dx,3D4h
- mov ax,14h ; Disable dword mode
- out dx,ax
- mov ax,0E317h ; Enable byte mode.
- out dx,ax
- out dx,ax
- mov ax,00409h ; Cell height
- out dx,ax
-
- mov si, offset [pallette]
- mov dx, 3c8h ; Pallette write register
- mov al, 0
- out dx, al ; Start at color zero
- inc dx
- mov cx, 768
- @PalLoop :
- outsb ; Write value to port; inc DI
- dec cx
- jnz @PalLoop
- ret
-
- SetUpScreen endp
-
-
-
- START:
- mov ax,@DATA
- mov ds,ax ; Moves the segment of the data into DS.
-
- call SetUpScreen
-
- mov randseed,1234h
- mov si,offset [screen]
- mov cx,xsize*ysize
- xor ax,ax
- rep stosb ; Clear our virtual screen.
-
- @MainLoop :
-
- ;
- ; This next bit puts either 0 or 255 along the very
- ; bottom row of our virtual screen.
- ;
-
- mov si,offset [screen]
- add si,xsize*ysize
- sub si,xsize ; si=ofs(screen)+xsize*ysize-xsize ie. start of last row
- mov cx,xsize ; loop the entire last row
- xor dx,dx
- @Newline :
- call random
- mov ds:[si],dl
- inc si
- dec cx
- jnz @Newline
-
- ;
- ; This "softens" the values in the virtual array,
- ; creating a fire effect.
- ;
- mov cx,xsize*ysize
- sub cx,xsize
- mov si,offset [screen]
- add si,xsize
- @FileLoop :
- xor ax,ax
- mov al,ds:[si]
- add al,ds:[si+1]
- adc ah,0
- add al,ds:[si-1]
- adc ah,0
- add al,ds:[si+xsize]
- adc ah,0
- shr ax,2
- jz @zero
- dec ax
- @Zero :
- ; al = ((pos)+(pos+1)+(pos-1)+(pos+80))/4 - 1
- mov ds:[si-xsize],al
- inc si
- dec cx
- jnz @FileLoop
-
- ;
- ; This dumps our virtual screen to the VGA screen.
- ;
- mov dx, 3dah
- l1:
- in al, dx
- and al, 8h
- jnz l1
- l2:
- in al, dx
- and al, 8h
- jz l2
-
- mov cx,xsize*ysize
- shr cx,1
- mov si,offset [screen]
- xor di,di
- rep movsw
-
- mov ah,01
- int 16h ; Has a key been pressed?
- jz @MainLoop ; If not, carry on.
-
- mov ah,0
- int 16h ;get a key, returned in AX
- ;this is just to clear the keyboard buffer of the key
- ;press.
-
- mov ax,0003h
- int 10h ; Get into 80x25 text mode
-
- mov dx,offset [endmessage]
- mov ah,09h
- int 21h ; Dos interrupt 21, subfunction 09 ... print string.
- ; DS:DX must be pointing to start of string.
-
- mov ax,4c00h ; This function exits the program
- int 21h ; and returns control to DOS.
- END START
-
- fire db 0, 0, 0, 0, 0, 6, 0, 0, 6, 0, 0, 7, 0, 0, 8, 0
- db 0, 8, 0, 0, 9, 0, 0, 10, 2, 0, 10, 4, 0, 9, 6, 0
- db 9, 8, 0, 8, 10, 0, 7, 12, 0, 7, 14, 0, 6, 16, 0, 5
- db 18, 0, 5, 20, 0, 4, 22, 0, 4, 24, 0, 3, 26, 0, 2, 28
- db 0, 2, 30, 0, 1, 32, 0, 0, 32, 0, 0, 33, 0, 0, 34, 0
- db 0, 35, 0, 0, 36, 0, 0, 36, 0, 0, 37, 0, 0, 38, 0, 0
- db 39, 0, 0, 40, 0, 0, 40, 0, 0, 41, 0, 0, 42, 0, 0, 43
- db 0, 0, 44, 0, 0, 45, 0, 0, 46, 1, 0, 47, 1, 0, 48, 2
- db 0, 49, 2, 0, 50, 3, 0, 51, 3, 0, 52, 4, 0, 53, 4, 0
- db 54, 5, 0, 55, 5, 0, 56, 6, 0, 57, 6, 0, 58, 7, 0, 59
- db 7, 0, 60, 8, 0, 61, 8, 0, 63, 9, 0, 63, 9, 0, 63, 10
- db 0, 63, 10, 0, 63, 11, 0, 63, 11, 0, 63, 12, 0, 63, 12, 0
- db 63, 13, 0, 63, 13, 0, 63, 14, 0, 63, 14, 0, 63, 15, 0, 63
- db 15, 0, 63, 16, 0, 63, 16, 0, 63, 17, 0, 63, 17, 0, 63, 18
- db 0, 63, 18, 0, 63, 19, 0, 63, 19, 0, 63, 20, 0, 63, 20, 0
- db 63, 21, 0, 63, 21, 0, 63, 22, 0, 63, 22, 0, 63, 23, 0, 63
- db 24, 0, 63, 24, 0, 63, 25, 0, 63, 25, 0, 63, 26, 0, 63, 26
- db 0, 63, 27, 0, 63, 27, 0, 63, 28, 0, 63, 28, 0, 63, 29, 0
- db 63, 29, 0, 63, 30, 0, 63, 30, 0, 63, 31, 0, 63, 31, 0, 63
- db 32, 0, 63, 32, 0, 63, 33, 0, 63, 33, 0, 63, 34, 0, 63, 34
- db 0, 63, 35, 0, 63, 35, 0, 63, 36, 0, 63, 36, 0, 63, 37, 0
- db 63, 38, 0, 63, 38, 0, 63, 39, 0, 63, 39, 0, 63, 40, 0, 63
- db 40, 0, 63, 41, 0, 63, 41, 0, 63, 42, 0, 63, 42, 0, 63, 43
- db 0, 63, 43, 0, 63, 44, 0, 63, 44, 0, 63, 45, 0, 63, 45, 0
- db 63, 46, 0, 63, 46, 0, 63, 47, 0, 63, 47, 0, 63, 48, 0, 63
- db 48, 0, 63, 49, 0, 63, 49, 0, 63, 50, 0, 63, 50, 0, 63, 51
- db 0, 63, 52, 0, 63, 52, 0, 63, 52, 0, 63, 52, 0, 63, 52, 0
- db 63, 53, 0, 63, 53, 0, 63, 53, 0, 63, 53, 0, 63, 54, 0, 63
- db 54, 0, 63, 54, 0, 63, 54, 0, 63, 54, 0, 63, 55, 0, 63, 55
- db 0, 63, 55, 0, 63, 55, 0, 63, 56, 0, 63, 56, 0, 63, 56, 0
- db 63, 56, 0, 63, 57, 0, 63, 57, 0, 63, 57, 0, 63, 57, 0, 63
- db 57, 0, 63, 58, 0, 63, 58, 0, 63, 58, 0, 63, 58, 0, 63, 59
- db 0, 63, 59, 0, 63, 59, 0, 63, 59, 0, 63, 60, 0, 63, 60, 0
- db 63, 60, 0, 63, 60, 0, 63, 60, 0, 63, 61, 0, 63, 61, 0, 63
- db 61, 0, 63, 61, 0, 63, 62, 0, 63, 62, 0, 63, 62, 0, 63, 62
- db 0, 63, 63, 0, 63, 63, 1, 63, 63, 2, 63, 63, 3, 63, 63, 4
- db 63, 63, 5, 63, 63, 6, 63, 63, 7, 63, 63, 8, 63, 63, 9, 63
- db 63, 10, 63, 63, 10, 63, 63, 11, 63, 63, 12, 63, 63, 13, 63, 63
- db 14, 63, 63, 15, 63, 63, 16, 63, 63, 17, 63, 63, 18, 63, 63, 19
- db 63, 63, 20, 63, 63, 21, 63, 63, 21, 63, 63, 22, 63, 63, 23, 63
- db 63, 24, 63, 63, 25, 63, 63, 26, 63, 63, 27, 63, 63, 28, 63, 63
- db 29, 63, 63, 30, 63, 63, 31, 63, 63, 31, 63, 63, 32, 63, 63, 33
- db 63, 63, 34, 63, 63, 35, 63, 63, 36, 63, 63, 37, 63, 63, 38, 63
- db 63, 39, 63, 63, 40, 63, 63, 41, 63, 63, 42, 63, 63, 42, 63, 63
- db 43, 63, 63, 44, 63, 63, 45, 63, 63, 46, 63, 63, 47, 63, 63, 48
- db 63, 63, 49, 63, 63, 50, 63, 63, 51, 63, 63, 52, 63, 63, 52, 63
- db 63, 53, 63, 63, 54, 63, 63, 55, 63, 63, 56, 63, 63, 57, 63, 63
- db 58, 63, 63, 59, 63, 63, 60, 63, 63, 61, 63, 63, 62, 63, 63, 63